%%%-------------------------------------------------------------------
%%% @author Viktor Green <viktor@localhost>
%%% @copyright (C) 2011, Viktor Green
%%% @doc
%%%
%%% @end
%%% Created : 14 Dec 2011 by Viktor Green <viktor@localhost>
%%%-------------------------------------------------------------------
-module(torrent_sup).

-behaviour(supervisor).

%% API
-export([start_link/3, start_tracking/4,
	 get_filehandler/1, get_ctrl/1,
	 start_peer_connections/3]).

%% Supervisor callbacks
-export([init/1]).

-include("records.hrl").

-define(SERVER, ?MODULE).

-define(CHILD(I, Type, Args), {I, {I, start_link, Args},
			       permanent, 5000, Type, [I]}).

%%%===================================================================
%%% API functions
%%%===================================================================

%%--------------------------------------------------------------------
%% @doc
%% Starts the supervisor
%%
%% @end
%%--------------------------------------------------------------------
-spec start_link(Torrent :: #torrent{},
		 Target :: string(), Allocate :: boolean()) ->
			{ok, Pid :: pid()} | 
			ignore |
			{error, Error :: term()}.
start_link(Torrent, Target, FileExists) ->
    supervisor:start_link(?MODULE, [Torrent, Target, FileExists]).

%%--------------------------------------------------------------------
%% @doc
%% Start the tracker child of this supervisor
%% @end
%%--------------------------------------------------------------------
-spec start_tracking(Pid :: pid(), Torrent :: #torrent{},
		     Left :: integer(), Ctrl :: pid()) ->
			    supervisor:startchild_ret().
start_tracking(Pid, Torrent, Left, Ctrl) ->
    TrackerChild = ?CHILD(tracker_srv, worker, [Torrent, Left, Ctrl]),
    supervisor:start_child(Pid, TrackerChild).

%%--------------------------------------------------------------------
%% @doc
%% Add peer supervisor as child to this supervisor
%% @end
%%--------------------------------------------------------------------
-spec start_peer_connections(Pid :: pid(), PeerRef :: tracker:address(),
			     Socket :: gen_tcp:socket()) ->
				    {ok, Child :: pid()}.
start_peer_connections(Pid, PeerRef, Socket) ->
    Peer = {PeerRef, {peer_sup, start_link, [Socket]},
	    permanent, infinity, supervisor, [peer_sup]},
    {ok, Child} = supervisor:start_child(Pid, Peer),
    Children = supervisor:which_children(Child),
    case lists:keyfind(peer_recv, 1, Children) of
	false -> ok;
	{peer_recv, Recv, _, _} ->
	    gen_tcp:controlling_process(Socket, Recv),
	    inet:setopts(Socket, [{active, true}])
    end,
    {ok, Child}.

%%--------------------------------------------------------------------
%% @doc
%% Function to get the pid of the file_handler that this supervisor
%% supervises.
%% @end
%%--------------------------------------------------------------------
-spec get_filehandler(Pid :: pid()) -> Pid :: pid() | undefined.
get_filehandler(Pid) ->
    case lists:keyfind(file_handler, 1, supervisor:which_children(Pid)) of
	false -> undefined;
	{file_handler, Child, _, _} -> Child
    end.

%%--------------------------------------------------------------------
%% @doc
%% Function to get the pid of the torrent_ctrl that this supervisor
%% supervises.
%% @end
%%--------------------------------------------------------------------
-spec get_ctrl(Pid :: pid()) -> Pid :: pid() | undefined.
get_ctrl(Pid) ->
    case lists:keyfind(torrent_ctrl, 1, supervisor:which_children(Pid)) of
	false -> undefined;
	{torrent_ctrl, Child, _, _} -> Child
    end.

%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever a supervisor is started using supervisor:start_link/[2,3],
%% this function is called by the new process to find out about
%% restart strategy, maximum restart frequency and child
%% specifications.
%%
%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} |
%%                     ignore |
%%                     {error, Reason}
%% @end
%%--------------------------------------------------------------------
init([Torrent, Target, FileExists]) ->
    Ctrl = ?CHILD(torrent_ctrl, worker, [Torrent,
					 FileExists, self()]),
    File = ?CHILD(file_handler, worker, [Target]),
    {ok, {{one_for_all, 1, 60}, [Ctrl, File]}}.

%%%===================================================================
%%% Internal functions
%%%===================================================================
